﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Collections;
using System.Xml.Linq;

namespace EntityFramework.PEM
{
    /// <summary>
    /// Class Library used to extract Data Annotation from EDMX files
    /// Prerequisite: Portable Extensible Metadata Extension (http://blogs.msdn.com/b/adonet/archive/2010/01/13/introducing-the-portable-extensible-metadata.aspx)
    /// </summary>
    public class PEMDataAnnotation
    {
        /// <summary>
        /// Generate Data Annotation from PEM information from especific property from an entity.
        /// Reads Display and Validation data from csdl contained into EDMX.
        /// </summary>
        /// <param name="entityName">Entity Name</param>
        /// <param name="propertyName">Property Name</param>
        /// <param name="path">Path of EDMX file</param>
        /// <returns></returns>
        public static string GenerateDataAnnotationsFromEDMX(string entityName, string propertyName, string path)
        {
            List<string> resultList = new List<string>();

            XDocument edmxDoc = XDocument.Load(path);

            XElement csdlContent = null;
            XNamespace edmxns = "http://schemas.microsoft.com/ado/2008/10/edmx";
            XNamespace edmns = "http://schemas.microsoft.com/ado/2008/09/edm";
            XNamespace pemns = "http://schemas.microsoft.com/PEM/2009/01";

            csdlContent = edmxDoc.Descendants(edmns + "Schema").FirstOrDefault();

            if (csdlContent != null)
            {
                var entityType = csdlContent.Elements(edmns + "EntityType").Where(p => p.Attribute("Name").Value == entityName).FirstOrDefault();
                var property = entityType.Elements(edmns + "Property").Where(p => p.Attribute("Name").Value == propertyName).FirstOrDefault();

                // Display
                var display = property.Element(pemns + "Display");
                if (display != null)
                {
                    List<string> displayItems = new List<string>();

                    // Name
                    var Name = display.Attributes("Name").FirstOrDefault();
                    if (Name != null)
                        displayItems.Add(@"Name = """ + Name.Value + @"""");

                    // GroupName
                    var GroupName = display.Attributes("GroupName").FirstOrDefault();
                    if (GroupName != null)
                        displayItems.Add(@"GroupName = """ + GroupName.Value + @"""");

                    // Description
                    var Description = display.Attributes("Description").FirstOrDefault();
                    if (Description != null)
                        displayItems.Add(@"Description = """ + Description.Value + @"""");

                    // Prompt
                    var Prompt = display.Attributes("Prompt").FirstOrDefault();
                    if (Prompt != null)
                        displayItems.Add(@"Prompt = """ + Prompt.Value + @"""");

                    // Visible
                    var Visible = display.Attributes("Visible").FirstOrDefault();
                    if (Visible != null)
                        displayItems.Add("AutoGenerateField = " + Visible.Value.ToLower());

                    // Order
                    var Order = display.Attributes("Order").FirstOrDefault();
                    if (Order != null)
                        displayItems.Add(@"Order = " + Order.Value);

                    // Generate display item
                    if (displayItems.Any())
                        resultList.Add("[Display(" + string.Join(", ", displayItems) + ")]");

                    // Editable
                    var Editable = display.Attributes("Editable").FirstOrDefault();
                    if (Editable != null)
                        resultList.Add("[Editable(" + Editable.Value.ToLower() + ")]");
                }

                // Validations
                var validations = property.Element(pemns + "Validations");
                if (validations != null && validations.HasElements)
                {
                    var dataFieldLength = validations.Element(pemns + "DataFieldLength");
                    if (dataFieldLength != null)
                    {
                        // [StringLength(10, MinimumLength = 4, ErrorMessage="")]

                        List<string> stringLengthItems = new List<string>();

                        var maximumLength = dataFieldLength.Attributes("MaximumLength").FirstOrDefault();
                        if (maximumLength != null)
                            stringLengthItems.Add(maximumLength.Value);

                        var minimumLength = dataFieldLength.Attributes("MinimumLength").FirstOrDefault();
                        if (minimumLength != null)
                            stringLengthItems.Add(@"MinimumLength = " + minimumLength.Value);

                        var errorMessage = dataFieldLength.Attributes("ErrorMessage").FirstOrDefault();
                        if (errorMessage != null)
                            stringLengthItems.Add(@"ErrorMessage = """ + errorMessage.Value + @"""");

                        resultList.Add("[StringLength(" + string.Join(", ", stringLengthItems) + ")]");
                    }

                    var regularExpression = validations.Element(pemns + "RegularExpression");
                    if (regularExpression != null)
                    {
                        // [RegularExpression(@"\d{11}", ErrorMessage = "")]

                        List<string> regularExpressionItems = new List<string>();

                        var pattern = regularExpression.Attributes("Pattern").FirstOrDefault();
                        if (pattern != null)
                            regularExpressionItems.Add(@"@""" + pattern.Value + @"""");

                        var errorMessage = regularExpression.Attributes("ErrorMessage").FirstOrDefault();
                        if (errorMessage != null)
                            regularExpressionItems.Add(@"ErrorMessage = """ + errorMessage.Value + @"""");

                        resultList.Add("[RegularExpression(" + string.Join(", ", regularExpressionItems) + ")]");
                    }

                    // THERE's NO COMPATIBLE DATA ANNOTATION FOR inSet, so this validation is ignored. Maybe a future regex implementation.
                    //var inSet = validations.Element(pemns + "inSet");
                    //if (inSet != null)
                    //{
                    //}

                    var required = validations.Element(pemns + "Required");
                    if (required != null)
                    {
                        // [Required(ErrorMessage = "")]
                        var errorMessage = required.Attributes("ErrorMessage").FirstOrDefault();

                        resultList.Add(@"[Required(ErrorMessage = """ + errorMessage.Value + @""")]");
                    }
                }
            }

            return string.Join("\r\n", resultList);
        }
    }
}
